﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace JavascriptWebResourcesManager
{
    /// <summary>
    /// Class that manages action on scripts web resources
    /// in Microsoft Dynamics CRM 2011
    /// </summary>
    internal class ScriptManager
    {
        #region Variables
        
        /// <summary>
        /// Xrm Organization service
        /// </summary>
        IOrganizationService innerService;

        #endregion Variables

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class ScriptManager
        /// </summary>
        /// <param name="service">Xrm Organization service</param>
        public ScriptManager(IOrganizationService service)
        {
            this.innerService = service;
        }

        #endregion Constructor

        #region Methods

        /// <summary>
        /// Retrieves all scripts web resources that are customizable
        /// </summary>
        /// <returns>List of scripts</returns>
        internal EntityCollection RetrieveScripts()
        {
            try
            {
                QueryByAttribute qba = new QueryByAttribute("webresource");
                qba.ColumnSet = new ColumnSet(true);
                //qba.Attributes.AddRange(new string[] { "webresourcetype", "iscustomizable" });
                //qba.Values.AddRange(new object[] { 3, true });
                qba.Attributes.AddRange(new string[] { "webresourcetype", "ishidden" , "ismanaged" });
                qba.Values.AddRange(new object[] { 3 , false, false});

                return this.innerService.RetrieveMultiple(qba);
            }
            catch (Exception error)
            {
                throw new Exception("Error while retrieving scripts: " + error.Message);
            }
        }

        /// <summary>
        /// Retrieves a specific script from its unique identifier
        /// </summary>
        /// <param name="scriptId">Script unique identifier</param>
        /// <returns>Script</returns>
        internal Entity RetrieveScript(Guid scriptId)
        {
            try
            {
                return this.innerService.Retrieve("webresource", scriptId, new ColumnSet(true));
            }
            catch (Exception error)
            {
                throw new Exception("Error while retrieving script: " + error.Message);
            }
        }

        /// <summary>
        /// Retrieves a specific script from its unique name
        /// </summary>
        /// <param name="name">Script unique name</param>
        /// <returns>Script</returns>
        internal Entity RetrieveScript(string name)
        {
            try
            {
                QueryByAttribute qba = new QueryByAttribute("webresource");
                qba.Attributes.Add("name");
                qba.Values.Add(name);
                qba.ColumnSet = new ColumnSet(true);

                EntityCollection collection = this.innerService.RetrieveMultiple(qba);

                if (collection.Entities.Count == 0)
                {
                    return null;
                }
                else if (collection.Entities.Count > 1)
                {
                    throw new Exception(string.Format("there are more than one script with name '{0}'", name));
                }
                else
                {
                    return collection[0];
                }
            }
            catch (Exception error)
            {
                throw new Exception("Error while retrieving script: " + error.Message);
            }
        }

        /// <summary>
        /// Updates the provided script
        /// </summary>
        /// <param name="script">Script to update</param>
        internal void UpdateScript(Entity script)
        {
            try
            {
                this.innerService.Update(script);
            }
            catch (Exception error)
            {
                throw new Exception("Error while updating script: " + error.Message);
            }
        }

        /// <summary>
        /// Deletes the provided script
        /// </summary>
        /// <param name="script">Script to delete</param>
        internal void DeleteScript(Entity script)
        {
            try
            {
                this.innerService.Delete(script.LogicalName, script.Id);
            }
            catch (Exception error)
            {
                throw new Exception("Error while deleting script: " + error.Message);
            }
        }

        /// <summary>
        /// Creates the provided script
        /// </summary>
        /// <param name="script">Script to create</param>
        internal Guid CreateScript(Entity script)
        {
            try
            {
                script["webresourcetype"] = new OptionSetValue(3);
                return this.innerService.Create(script);
            }
            catch (Exception error)
            {
                throw new Exception("Error while creating script: " + error.Message);
            }
        }

        internal static string GetContentFromBase64String(string base64)
        {
            byte[] b = Convert.FromBase64String(base64);
            return System.Text.Encoding.UTF8.GetString(b);
        }

        internal static string GetBase64StringFromString(string content)
        {
            byte[] byt = System.Text.Encoding.UTF8.GetBytes(content);
            return Convert.ToBase64String(byt);
        }

        #endregion

        internal void PublishScript(Entity script)
        {
            try
            {
                PublishXmlRequest pxReq1 = new PublishXmlRequest
                {
                    ParameterXml = String.Format("<importexportxml><webresources><webresource>{0}</webresource></webresources></importexportxml>", script["webresourceid"].ToString())
                };

                this.innerService.Execute(pxReq1);
            }
            catch (Exception error)
            {
                throw new Exception("Error while publishing script: " + error.Message);
            }
        }
    }
}
